package com.bwstudio.common.unires.aspect;

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.UUID;

/**
 * @author BuWei
 */
@Slf4j
@Aspect
@Component
public class WebLogAspect {

    private Gson gson = new Gson();

    public static final ThreadLocal<Long>  startTime = new ThreadLocal<>();

    private static final String STR_THREAD_ID = "threadId";


    //申明一个切点 里面是 execution表达式
    @Pointcut("@within(com.bwstudio.common.unires.annotation.WebLog) || @annotation(com.bwstudio.common.unires.annotation.WebLog)")
    private void webLog() {
    }


    //请求method前打印内容
    @Before(value = "webLog()")
    public void methodBefore(JoinPoint joinPoint) {
        // 方法执行前加上线程号
        MDC.put(STR_THREAD_ID, UUID.randomUUID().toString().replaceAll("-", ""));
        startTime.set(System.currentTimeMillis());

        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();

        log.info("=============== Request Info ================");
        // 打印请求 url
        log.info("URL            : {}", request.getRequestURL().toString());
        // 打印 Http method
        log.info("HTTP Method    : {}", request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        // 打印请求的 IP
        log.info("IP             : {}", request.getRemoteAddr());
        // 打印请求入参
        log.info("Request Args   : {}", new Gson().toJson(joinPoint.getArgs()));
        log.info("=============== Request Info ================");

    }


    //在方法执行完结后打印返回内容
    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void methodAfterReturing(Object ret) {
        log.info("--------------- Response Succ Info ----------");
        log.info("Response Content  : {}", gson.toJson(ret));

        log.info("Request Succ Cost Time : {} {}", (System.currentTimeMillis() - startTime.get()), "ms");
        log.info("--------------- Response Succ Info ----------");

        startTime.remove();
        // 方法执行结束移除线程号
        MDC.remove(STR_THREAD_ID);
    }

    //在方法执行完结后打印返回内容
    @AfterThrowing(throwing = "ex", pointcut = "webLog()")
    public void methodAfterThrowing(JoinPoint joinPoint, Exception ex) {
        log.info("--------------- Response Exception ----------");

        log.info("Request Exception Cost Time : {} {}", (System.currentTimeMillis() - startTime.get()), "ms");
        log.info("--------------- Response Exception ----------");

        startTime.remove();
        // 方法执行结束移除线程号
        MDC.remove(STR_THREAD_ID);
    }

}
